﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DAWSharp.UI.WinFormsControls
{
    /// <summary>
    /// 
    /// </summary>
    public partial class HScroll : UserControl
    {
        /// <summary>
        /// The controls Zoom coefficient in percent
        /// </summary>
        public int Zoom
        {
            get
            {
                return normalizedZoomRatio;
            }
            set
            {
                if (0 > value)
                    value = 0;


                else if (value > 100)
                    value = 100;

                zoomRatio = (float)value / (100.0f);
                zoomLocation = new Point((int)Math.Floor(zoomRatio * zoomRange + (float)zoomMinXPos), 1);
                pbZoomHandle.Location = zoomLocation;
            }
        }

        /// <summary>
        /// The controls Position coefficient in percent.
        /// </summary>
        public int Position
        {
            get
            {
                return normalizedScrollRatio;
            }
            set
            {
                if (0 > value)
                    value = 0;


                else if (value > 100)
                    value = 100;

                scrollRange = (float)scrollbarMaxXPos - (float)scrollBarMinXPos;
                scrollRatio = (float)value / (100.0f);
                scrollBarLocation = new Point((int)Math.Floor(scrollRatio * scrollRange + (float)scrollBarMinXPos), 1);
                pnlScrollHandle.Location = scrollBarLocation;
            }
        }

        #region private variable declarations

        //Scroll Bar Positional variables
        private bool scrollBarDragging = false;
        private int scrollBarMouseDownX;
        private int scrollBarDragX;
        private Point scrollBarLocation = new Point(16, 1);
        private int scrollBarMinXPos = 16;
        private int scrollbarMaxXPos = 0;
        private int scrollBarMinWidth = 6;
        private int scrollBarMaxWidth = 10;

        //Scroll Bar maths variables
        private float scrollRange;
        private float scrollRatio;
        private int normalizedScrollRatio;

        //Zoom Control Positional variables
        private bool zoomDragging = false;
        private int zoomMouseDownX;
        private int zoomDragX;
        private Point zoomLocation = new Point(13, 1);
        private int zoomMinXPos = 13;
        private int zoomMaxXPos = 60;

        //Zoom Control maths variables
        private float zoomRange;
        private float zoomRatio;
        private int normalizedZoomRatio;

        private Timer incrementScrollBarTimer = new Timer() { Interval = 100, Enabled = false };
        private Timer decrementScrollBarTimer = new Timer() { Interval = 100, Enabled = false };


        #endregion

        /// <summary>
        /// Creates an instance of a HScroll object
        /// </summary>
        public HScroll()
        {
            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            InitializeComponent();

            incrementScrollBarTimer.Tick += (s, e) => IncrementScrollBarPosition();
            decrementScrollBarTimer.Tick += (s, e) => DecrementScrollBarPosition();

            this.Zoom = 0;
        }

        #region Private methods

        private void RecalculateSizes()
        {
            scrollbarMaxXPos = btnScrlR.Location.X - 1 - pnlScrollHandle.Width;
            scrollBarMaxWidth = btnScrlR.Location.X - btnScrlL.Width;

            scrollRange = (float)scrollbarMaxXPos - (float)scrollBarMinXPos;
            scrollRatio = (float)(pnlScrollHandle.Location.X - (float)scrollBarMinXPos) / scrollRange;
            normalizedScrollRatio = (int)Math.Floor(100 * scrollRatio);

            zoomRange = (float)zoomMaxXPos - (float)zoomMinXPos;
            zoomRatio = (float)(pbZoomHandle.Location.X - (float)zoomMinXPos) / zoomRange;
            normalizedZoomRatio = (int)Math.Floor(100 * zoomRatio);

            pnlScrollHandle.Width = (int)Math.Floor((((float)scrollBarMaxWidth) * (1.0f - zoomRatio)));

            if (pnlScrollHandle.Width < scrollBarMinWidth)
                pnlScrollHandle.Width = scrollBarMinWidth;

            if (pnlScrollHandle.Location.X + pnlScrollHandle.Width > btnScrlR.Location.X)
            {
                scrollBarLocation = new Point(btnScrlR.Location.X - pnlScrollHandle.Width, 1);
                pnlScrollHandle.Location = scrollBarLocation;
            }

            this.Refresh();
        }

        private void IncrementScrollBarPosition()
        {
            pnlScrollHandle.Location = new Point(pnlScrollHandle.Location.X + 5, 1);

            if (pnlScrollHandle.Location.X < scrollBarMinXPos)
                pnlScrollHandle.Location = new Point(scrollBarMinXPos, 1);
            else if (pnlScrollHandle.Location.X > scrollbarMaxXPos)
                pnlScrollHandle.Location = new Point(scrollbarMaxXPos, 1);

            RecalculateSizes();
        }

        private void DecrementScrollBarPosition()
        {
            pnlScrollHandle.Location = new Point(pnlScrollHandle.Location.X - 5, 1);

            if (pnlScrollHandle.Location.X < scrollBarMinXPos)
                pnlScrollHandle.Location = new Point(scrollBarMinXPos, 1);
            else if (pnlScrollHandle.Location.X > scrollbarMaxXPos)
                pnlScrollHandle.Location = new Point(scrollbarMaxXPos, 1);

            RecalculateSizes();
        }

        #endregion

        #region Event Handlers

        private void pnlScrollHandle_MouseDown(object sender, MouseEventArgs e)
        {
            scrollBarDragging = true;
            scrollBarDragX = e.X - pnlScrollHandle.Location.X;
            scrollBarMouseDownX = e.Y;
            base.OnMouseDown(e);
        }

        private void pnlScrollHandle_MouseUp(object sender, MouseEventArgs e)
        {
            scrollBarDragging = false;
            base.OnMouseUp(e);
            this.Refresh();
        }

        private void pnlScrollHandle_MouseMove(object sender, MouseEventArgs e)
        {
            if (scrollBarDragging)
            {
                scrollbarMaxXPos = btnScrlR.Location.X - 1 - pnlScrollHandle.Width;

                //Detect the direction the mouse is moving in follow it at the same velocity
                if (e.X > scrollBarMouseDownX)
                    scrollBarLocation = new Point(scrollBarLocation.X + (1 * e.X - scrollBarMouseDownX), 1);
                else if (e.X < scrollBarMouseDownX)
                    scrollBarLocation = new Point(scrollBarLocation.X - (1 * scrollBarMouseDownX - e.X), 1);

                if (scrollBarLocation.X < scrollBarMinXPos)
                    scrollBarLocation = new Point(scrollBarMinXPos, 1);
                else if (scrollBarLocation.X > scrollbarMaxXPos)
                    scrollBarLocation = new Point(scrollbarMaxXPos, 1);

                pnlScrollHandle.Location = scrollBarLocation;

                RecalculateSizes();
            }

            base.OnMouseMove(e);
        }

        private void btnScrlL_Click(object sender, EventArgs e)
        {
            DecrementScrollBarPosition();
        }

        private void btnScrlR_Click(object sender, EventArgs e)
        {
            IncrementScrollBarPosition();
        }

        private void btnScrlR_MouseDown(object sender, MouseEventArgs e)
        {
            incrementScrollBarTimer.Enabled = true;
        }

        private void btnScrlR_MouseUp(object sender, MouseEventArgs e)
        {
            incrementScrollBarTimer.Enabled = false;
        }

        private void btnScrlL_MouseDown(object sender, MouseEventArgs e)
        {
            decrementScrollBarTimer.Enabled = true;
        }

        private void btnScrlL_MouseUp(object sender, MouseEventArgs e)
        {
            decrementScrollBarTimer.Enabled = false;
        }

        private void pbZoomHandle_MouseDown(object sender, MouseEventArgs e)
        {
            zoomDragging = true;
            zoomDragX = e.X - pbZoomHandle.Location.X;
            zoomMouseDownX = e.Y;
            base.OnMouseDown(e);
        }

        private void pbZoomHandle_MouseUp(object sender, MouseEventArgs e)
        {
            zoomDragging = false;
            base.OnMouseUp(e);
            this.Refresh();
        }

        private void pbZoomHandle_MouseMove(object sender, MouseEventArgs e)
        {
            if (zoomDragging)
            {
                //Detect the direction the mouse is moving in follow it at the same velocity
                if (e.X > zoomMouseDownX)
                    zoomLocation = new Point(zoomLocation.X + (1 * e.X - zoomMouseDownX), 1);
                else if (e.X < scrollBarMouseDownX)
                    zoomLocation = new Point(zoomLocation.X - (1 * zoomMouseDownX - e.X), 1);

                if (zoomLocation.X < zoomMinXPos)
                    zoomLocation = new Point(zoomMinXPos, 1);
                else if (zoomLocation.X > zoomMaxXPos)
                    zoomLocation = new Point(zoomMaxXPos, 1);

                pbZoomHandle.Location = zoomLocation;
            }

            base.OnMouseMove(e);
        }

        private void pnlZoomBase_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Location.X < 10)
            {
                zoomLocation = new Point(pbZoomHandle.Location.X - 1, 1);
                pbZoomHandle.Location = zoomLocation;

                if (pbZoomHandle.Location.X < zoomMinXPos)
                    pbZoomHandle.Location = new Point(zoomMinXPos, 1);
                else if (pbZoomHandle.Location.X > zoomMaxXPos)
                    pbZoomHandle.Location = new Point(zoomMaxXPos, 1);
            }
            else if (e.Location.X > pnlZoomBase.Width - 10)
            {
                zoomLocation = new Point(pbZoomHandle.Location.X + 1, 1);
                pbZoomHandle.Location = zoomLocation;

                if (pbZoomHandle.Location.X < zoomMinXPos)
                    pbZoomHandle.Location = new Point(zoomMinXPos, 1);
                else if (pbZoomHandle.Location.X > zoomMaxXPos)
                    pbZoomHandle.Location = new Point(zoomMaxXPos, 1);
            }
        }

        private void pbZoomHandle_LocationChanged(object sender, EventArgs e)
        {
            RecalculateSizes();
        }

        private void HScroll_Resize(object sender, EventArgs e)
        {
            RecalculateSizes();
        }

        #endregion


    }
}
